const connectBtn = document.getElementById('connectBtn')
const leaveBtn = document.getElementById('leaveBtn')
const userName = document.getElementById('userName')
const localVideo = document.getElementById('localVideo')
const remoteVideo1 = document.getElementById('remoteVideo1')
const remoteVideo2 = document.getElementById('remoteVideo2')
const bandWidthSelect = document.getElementById('bandwidth')
const chatTextArea = document.getElementById("chatTextArea")
const chatInputArea = document.getElementById("chatInputArea")
const chatSendBtn = document.getElementById("chatSendBtn")

const videoElements = [remoteVideo1, remoteVideo2]

const ROOM = '222';
let socket;

const mediaStreamConstrants = {
    video: true,
    // audio: {
    //     echoCancellation: false,
    //     noiseSuppression: true,
    //     autoGainControl: false
    // }
    audio: false
}

let localStream

let state = 'init'
let users;
let peers = {}
let videos = {}
let channels = {}
let remoteStream

const offerOptions = {
    offerToReceiveAudio: false,
    offerToReceiveVideo: true
}

function sendMessage(message, socketId) {
    const user = userName.value
    console.log(`${user} send message:`);
    console.log(message);
    socket.emit("message", ROOM, user, message, socketId)
}

function createPeerConnection(id) {
    const pc = new RTCPeerConnection()
    pc.onicecandidate = (e) => {
        console.log("=================== onicecandidate:");
        console.log(e.candidate);
        if (e.candidate) {
            sendMessage({
                type: 'candidate',
                label: e.candidate.sdpMLineIndex,
                id: e.candidate.sdpMid,
                candidate: e.candidate.candidate
            })
        }
    }
    pc.ontrack = (e) => {
        console.log("received remote video:");
        console.log(e);
        for (let i = 0; i < videoElements.length; i++) {
            const ele = videoElements[i];
            if (!ele.srcObject) {
                videos[id] = ele
                ele.srcObject = e.streams[0];
                break;
            }
        }
    }

    pc.ondatachannel = (e) => {
        console.log("peer ondatachannel event...")
    }

    localStream.getTracks().forEach(stream => {
        pc.addTrack(stream, localStream)
    });

    // 创建data channel
    const channel = pc.createDataChannel("chatMsg", {
        negotiated: true,
        id:ROOM
    });
    channels[id] = channel
    channel.onmessage = (e) => {
        console.log(e.data)
        chatTextArea.value += e.data;
    }
    channel.onopen = (e) => {
        console.log("received channel onopen event...")
    }
    // 设置带宽
    change_bw(pc);
    return pc;
}

function closePeerConnection(pc) {
    if (pc) {
        pc.close()
        pc = null
    }
}

function closeMediaStream() {
    if (localStream && localStream.getTracks()) {
        localStream.getTracks().forEach(stream => {
            stream.stop()
        })
    }
    localStream = null
}

function conn() {
    const user = userName.value
    socket = io.connect('https://chris.mynatapp.cc/')
    // 进行事件监听
    socket.on("joined", (room, socketId, id) => {
        state = 'joined'
        console.log(`${id} join ${room},...`);
        if (id === user) return;
        // 进行媒体协商
        const pc = createPeerConnection(id)
        peers[id] = pc
        users[id] = socketId
        // 创建信令
        pc.createOffer(offerOptions).then(desc => {
            pc.setLocalDescription(desc)
            sendMessage(desc, socketId)
        }).catch(err => console.error(err))
        console.log(peers);
    })

    socket.on('userstatechange', (room, allUser) => {
        console.log('=================== userstatechange :');
        console.log(allUser);
        if (!users) {
            users = allUser
        }
        ////////////////////////
    })

    socket.on('message', (room, id, message) => {
        console.log("====================")
        if (id === user || !message) return;
        console.log(`${user} get message from ${id}:`);
        console.log(message);
        if (message.type === 'offer') {
            const pc = createPeerConnection(id);
            peers[id] = pc;
            pc.setRemoteDescription(new RTCSessionDescription(message))
            pc.createAnswer(offerOptions).then(desc => {
                pc.setLocalDescription(desc);
                sendMessage(desc, users[id])
            }).catch(err => console.error(err))
        } else if (message.type === 'answer') {
            peers[id].setRemoteDescription(new RTCSessionDescription(message))
        } else if (message.type === 'candidate') {
            const candidate = new RTCIceCandidate({
                candidate: message.candidate,
                sdpMLineIndex: message.label
            })
            peers[id].addIceCandidate(candidate)
        } else {

        }
    })

    socket.on('leave', (room, id) => {
        // 关闭其他人资源
        console.log(`${id} leave ${room}`);
        videos[id].srcObject = null
    })
    socket.emit('join', ROOM, user)
}

function start() {
    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) return;
    navigator.mediaDevices.getUserMedia(mediaStreamConstrants).then(stream => {
        // 当前video设置流数据
        localVideo.srcObject = stream
        // 保存流数据
        localStream = stream
        // 建立连接
        conn()
    }).catch(err => {
        console.error(err)
    })
}


function leave() {
    const user = userName.value
    if (socket) {
        socket.emit('leave', ROOM, user);
        socket.disconnect()
        socket = null
    }
    closePeerConnection(peers[user])
    closeMediaStream()
}



function change_bw(pc) {
    const bw = bandWidthSelect.value
    if(bw === "unlimited") return;
    const senders = pc.getSenders()
    console.log(senders)
    senders.forEach(sender => {
        if(sender && sender.track.kind === "video") {
            const params = sender.getParameters()
            console.log(params);
            if(params.encodings) {
                params.encodings[0].maxBitrate = bw * 1000
                sender.setParameters(params).then(() => console.log("set params success")).catch(err => console.error(err));
            }
        }
    })
}


function changeBwEvent(e) {
    Object.values(peers).forEach(pc => {
        change_bw(pc)
    })
}

function sendMsg() {
    const value = chatInputArea.value
    const user = userName.value;
    if(!value) return;
    // 发送
    const msg = `${user}: ${value}` + '\r\n'
    chatTextArea.value += msg
    Object.values(channels).forEach(channel => {
        channel.send(msg)
    })
    chatInputArea.value = ""
}





connectBtn.onclick = start
leaveBtn.onclick = leave
bandWidthSelect.onclick = changeBwEvent
chatSendBtn.onclick = sendMsg

window.onbeforeunload = (e) => {
    leave()
    return true
}